﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SVN.Net.Misc;

namespace SVN.Net.Controllers
{
    public class EditorController : ControllerBase
    {
        public EditorController()
            : base()
        {
        }

        public EditorController(Models.ISVNProvider svn)
            : base(svn)
        {
        }

        private Misc.FileWriter.IFileWriter _fileWriter;
        public Misc.FileWriter.IFileWriter FileWriter
        {
            get
            {
                if (_fileWriter == null)
                    _fileWriter = new Misc.FileWriter.LocalFileWriter();
                return _fileWriter;
            }
            set
            {
                _fileWriter = value;
            }
        }

        #region " Edit Single File "

        [AcceptVerbs("GET")]
        public ActionResult Edit(string repo)
        {
            string filename = GlobalApplication.GetName(repo);
            var r = SVN.Cat(repo, UID, PWD);

            if (r.Success)
            {
                ViewData["isnew"] = false;
                ViewData["repo"] = repo;
                ViewData["name"] = filename;
                ViewData.Model = r.Result;
            }
            else
                throw r.Error;

            return View("Editor");
        }

        [AcceptVerbs("POST")]
        public ActionResult Edit(string repo, string code, string message)
        {
            // Checkout the folder of the edited file.
            string localPath = string.Empty;
            string repoPath = GlobalApplication.GetPath(repo);
            var r = SVN.CheckOut(repoPath, UID, PWD, ref localPath);

            if (!r.Success)
                throw r.Error;
            
            // Write the code into the local file.
            string filename = System.IO.Path.Combine(localPath, GlobalApplication.GetName(repo));
            FileWriter.Write(filename, code);
            // Commit it into SVN.
            r = SVN.CommitSingleFile(localPath, message, UID, PWD);
            // Remove the local files.
            DeleteWorkingDir(localPath);

            if (!r.Success)
                throw r.Error;
            return RedirectToAction("Navigate", "Home", new { repo = GlobalApplication.GetPath(repo), uid = UID, pwd = UID });
        }

        #endregion

        #region " Rename File /Folder "
        
        [AcceptVerbs("GET")]
        public ActionResult Rename(string repo)
        {
            ViewData["repo"] = repo;
            ViewData["currentFileName"] = GlobalApplication.GetName(repo);
            ViewData["newFileName"] = ViewData["currentFileName"];

            return View("Rename");
        }

        [AcceptVerbs("POST")]
        public ActionResult Rename(string repo, string currentFileName, string newFileName, string message)
        {
            newFileName = newFileName.Trim();
            var path = GlobalApplication.GetPath(repo);
            var dest = GlobalApplication.Combine(path, newFileName);

            // Backup the information.
            ViewData["repo"] = repo;
            ViewData["currentFileName"] = currentFileName;
            ViewData["newFileName"] = newFileName;
            ViewData["message"] = message;

            // Validation check for the new file name.
            CheckFileFolderName(dest, "newFileName");

            if (ViewData.ModelState.IsValid)
            {
                var r = SVN.Move(repo, dest, message, UID, PWD);
                if (!r.Success)
                    throw r.Error;
                return RedirectToAction("Navigate", "Home", new { repo = GlobalApplication.GetPath(repo), uid = UID, pwd = UID });
            }
            else
                return View("Rename");
        }

        #endregion

        #region " Delete File /Folder "

        public ActionResult Delete(string repo)
        {
            var r = SVN.Delete(repo, UID, PWD);
            if (!r.Success)
                throw r.Error;

            return RedirectToAction("Navigate", "Home", new { repo = GlobalApplication.GetPath(repo), uid = UID, pwd = UID });
        }

        #endregion

        #region " Create File /Folder "

        [AcceptVerbs("GET")]
        public ActionResult CreateFolder(string repo)
        {
            ViewData["repo"] = repo;

            return View("NewFolder");
        }

        [AcceptVerbs("POST")]
        public ActionResult CreateFolder(string repo, string folderName, string message)
        {
            // Backup the information
            ViewData["repo"] = repo;
            ViewData["folderName"] = folderName;
            ViewData["message"] = message;

            var dest = GlobalApplication.Combine(repo, folderName);
            // Check the foler name.
            CheckFileFolderName(dest, "folderName");

            if (ViewData.ModelState.IsValid)
            {
                var r = SVN.MakeDir(GlobalApplication.Combine(repo, folderName), message, UID, PWD);
                if (!r.Success)
                    throw r.Error;
                return RedirectToAction("Navigate", "Home", new { repo = repo, uid = UID, pwd = UID });
            }
            return View("NewFolder");
        }

        [AcceptVerbs("GET")]
        public ActionResult CreateFile(string repo)
        {
            string url = repo;
            string filename = string.Empty;

            ViewData["isnew"] = true;
            ViewData["repo"] = repo;
            ViewData["name"] = filename;
            ViewData.Model = string.Empty;

            return View("Editor");
        }

        [AcceptVerbs("POST")]
        public ActionResult CreateFile(string repo, string name, string code, string message)
        {
            // Backup the information.
            ViewData["isnew"] = true;
            ViewData["repo"] = repo;
            ViewData["name"] = name;
            ViewData.Model = code;
            ViewData["message"] = message;

            var dest = GlobalApplication.Combine(repo, name);
            // Check the new file name.
            CheckFileFolderName(dest, "name");
            
            // Checkout the folder of the new file.
            string localPath = string.Empty;
            string repoPath = repo;
            var r = SVN.CheckOut(repoPath, UID, PWD, ref localPath);

            if (!r.Success)
                throw r.Error;

            if (ViewData.ModelState.IsValid)
            {
                // Write the code into the loca file.
                string filename = System.IO.Path.Combine(localPath, name);
                System.IO.FileStream fs = null;
                System.IO.StreamWriter sw = null;
                try
                {
                    if (System.IO.File.Exists(filename))
                        fs = System.IO.File.Open(filename, System.IO.FileMode.Truncate, System.IO.FileAccess.Write);
                    else
                        fs = System.IO.File.Open(filename, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write);
                    sw = new System.IO.StreamWriter(fs);
                    sw.Write(code);
                }
                catch
                {
                    throw;
                }
                finally
                {
                    if (sw != null)
                        sw.Close();
                    if (fs != null)
                        fs.Close();
                }
                // Add to SVN.
                r = SVN.Add(filename, UID, PWD);
                // Commit to SVN.
                SVN.CommitSingleFile(localPath, message, UID, PWD);
                // Remove the local files.
                DeleteWorkingDir(localPath);

                if (!r.Success)
                    throw r.Error;
                return RedirectToAction("Navigate", "Home", new { repo = repo, uid = UID, pwd = UID });
            }
            else
                return View("Editor");
        }

        #endregion

        public ActionResult Cancel(string repo)
        {
            return RedirectToAction("Navigate", "Home", new { repo = GlobalApplication.GetPath(repo), uid = UID, pwd = UID });
        }

        private void CheckFileFolderName(string dest, string controlName)
        {
            string name = GlobalApplication.GetName(dest);
            if (string.IsNullOrEmpty(name))
                ViewData.ModelState.AddModelError(controlName, "Mandatory field.");
            else if (name.Contains('@'))
                ViewData.ModelState.AddModelError(controlName, "Contains invalid char.");
            else if (SVN.Exist(dest, UID, PWD))
                ViewData.ModelState.AddModelError(controlName, "Existed on the server side.");
        }
    }
}
